﻿using System.Collections.Generic;
using System.Linq;

namespace Borg.Framework
{
    public static class PlugInfoEx
    {
        private static bool Contains<T>(IEnumerable<T> array, T item)
        {
            return array != null && array.Any(t => !t.Equals(item));
        }

        public static PlugInfo FindPlug(PlugInfo plug, string slotName)
        {
            var list = new List<ExtensionInfo>();

            foreach (var slot in plug.PluggedInSlots.Where(slot => !list.Contains(slot.ExtensionInfo)))
            {
                list.Add(slot.ExtensionInfo);
                var plugInfo = ExtensionInfoEx.FindIncomingPlugTransitive(slot.ExtensionInfo, slotName);

                if (plugInfo != null)
                    return plugInfo;
            }

            return null;
        }

        public static PlugInfo FindPlug2(PlugInfo plug, string slotName)
        {
            if (plug.Name.Equals(slotName))
                return plug;

            return (from slot in plug.PluggedInSlots
                    from plugInfo in slot.ExtensionInfo.PlugInfos
                    select FindPlug2(plugInfo, slotName)).FirstOrDefault(info3 => info3 != null);
        }

        public static SlotInfo FindSlot(PlugInfo plug, string slotName)
        {
            return FindSlot(plug, slotName, null);
        }

        public static SlotInfo FindSlot(PlugInfo plug, string slotName, PlugTypeInfo[] filter)
        {
            var slotType = Runtime.Repository.SlotTypeInfos[slotName];

            return slotType != null
                ? FindSlot(slotType, plug, filter, new List<PlugInfo>())
                : null;
        }

        internal static SlotInfo FindSlot(SlotTypeInfo slotType, PlugInfo plug,
            PlugTypeInfo[] filter, List<PlugInfo> visited)
        {
            if (!visited.Contains(plug))
            {
                visited.Add(plug);

                if (!(filter == null || Contains(filter, plug.PlugTypeInfo)))
                    return null;

                foreach (var slot in plug.PluggedInSlots)
                {
                    foreach (var si in slot.ExtensionInfo.SlotInfos.
                        Where(si => si.SlotTypeInfo.Name == slotType.Name))
                        return si;

                    foreach (var pi in slot.ExtensionInfo.PlugInfos)
                    {
                        var slotInfo = FindSlot(slotType, pi, filter, visited);

                        if (slotInfo != null)
                            return slotInfo;
                    }
                }
            }
            return null;
        }
    }
}

